import re
from sqlalchemy.orm.interfaces import MapperExtension

class InvalidDataException(Exception):
    def __init__(self, instance, errors=dict(), *args):
        super(InvalidDataException, self).__init__(*args)
        self._instance = instance
        self._errors = errors
        
    #Errors property    
    def _get_errors(self):
        return self._errors
    Errors = property(_get_errors)
    ###
    
    #instance property
    def _get_instance(self):
        return self._instance
    Instance = property(_get_instance)
    ###

class Validator(object):
    def __init__(self, column, message=None):
        self._column = column
        self._message = message
    
    def __call__(self, instance):
        pass
    
    #column property
    def _get_column(self):
        return self._column
    Column = property(_get_column)
    ###
    
    #message property
    def _get_message(self):
        return self._message
    Message = property(_get_message)
    ###
    
    
class Regex(Validator):
    def __init__(self, column, pattern, message=None, *flags):
        if (message == None):
            message = "doesn't match the pattern"
        
        super(Regex, self).__init__(column, message)
        
        self._pattern = pattern
        self._flags = flags

    def __call__(self, instance):
        value = getattr(instance, self.Column)
        
        if (not self._re_search(value)):
            return False
        
        return True
    
    def _re_search(self, value):
        search = None
        
        #check value
        if (value == None):
            value = ""
        else:
            value = str(value)
        ####
        
        if (len(self._flags) > 0):
            flags = map(lambda f: str(f), self._flags)
            search = re.search(self._pattern, value, eval("|".join(flags)))
        else:
            search = re.search(self._pattern, value)
            
        return search

class ExtValidators(MapperExtension):
    def __init__(self, *args):
        MapperExtension.__init__(self)
        
        self._validations = args
        
    def before_insert(self, mapper, connection, instance):
        errors = dict() #dictionary with, column: error message
        
        for validation in self._validations:
            if (not validation(instance)):
                errors[validation.Column] = validation.Message
        
        #raise an exception in case of errors
        if (len(errors) > 0):
            raise InvalidDataException(instance, errors, "invalid values on object.")
        
        return EXT_CONTINUE
    before_update = before_insert